package com.example.plist.service.impl;

import com.alibaba.druid.sql.visitor.functions.Char;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.plist.db.mapper.GraphProjectContextMapper;
import com.example.plist.db.mapper.GraphProjectImageMapper;
import com.example.plist.db.mapper.GraphProjectMapper;
import com.example.plist.db.pojo.GraphProject;
import com.example.plist.db.pojo.GraphProjectContext;
import com.example.plist.db.pojo.GraphProjectImage;
import com.example.plist.dto.ExportDTO;
import com.example.plist.dto.ImageFileDTO;
import com.example.plist.dto.ProjectContextDTO;
import com.example.plist.dto.TransFormDTO;
import com.example.plist.service.GraphProjectService;
import com.example.plist.util.CosFile;
import com.example.plist.vo.GraphProjectVO;
import com.google.gson.Gson;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.*;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.Upload;
import com.qcloud.cos.utils.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.sql.Blob;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class GraphProjectServiceImpl implements GraphProjectService {
    @Resource
    private GraphProjectContextMapper contextMapper;
    @Resource
    private GraphProjectImageMapper imageMapper;
    @Resource
    private GraphProjectMapper projectMapper;
    @Override
    public GraphProjectVO findByProjectId(Integer id) {
        GraphProjectImage result =null;
        GraphProjectVO graphProjectVO = new GraphProjectVO();
        LambdaQueryWrapper<GraphProjectImage> queryWrapper = new LambdaQueryWrapper<GraphProjectImage>();
        queryWrapper.eq(GraphProjectImage::getProjectId,id);
        result = imageMapper.selectOne(queryWrapper);




        LambdaQueryWrapper<GraphProjectContext> queryWrapperContext = new LambdaQueryWrapper<GraphProjectContext>();
        queryWrapperContext.eq(GraphProjectContext::getProjectId,id);
        List<GraphProjectContext> list =contextMapper.selectList(queryWrapperContext);



        if(null == result){
            result = new GraphProjectImage();
        }
        if(null==list){
            list = new ArrayList<>();
        }




            list.forEach(context -> {
                context.setTransform(jsonToObj(context.getTransform(),TransFormDTO.class));
                context.setScale(jsonStrToMap(context.getScale()));
                context.setProperty(jsonStrToMap(context.getProperty()));
            });
            graphProjectVO.setImage(result);
            graphProjectVO.setList(list);


        return graphProjectVO;
    }
    InputStream getFileStream(String key,FileStreamProcess fileStreamProcess) throws IOException {
        CosFile cosFile = new CosFile();
        COSObjectInputStream cosObjectInput =null;
        COSClient client =null;
        try {
            client = cosFile.GetCosClient();
            GetObjectRequest getObjectRequest = new GetObjectRequest(cosFile.getBucket(), key);
            COSObject cosObject = client.getObject(getObjectRequest);
            cosObjectInput = cosObject.getObjectContent();
            fileStreamProcess.process(cosObjectInput);
            return  null;


    }catch (Exception e){
        System.out.println(e);
    }finally {
            if(null!=cosObjectInput){
                cosObjectInput.close();
            }

            client.shutdown();
        }

        return null;
    }
    String writeFile(ProjectContextDTO data, InputStream in,Long contextLength){

        CosFile cosFile = new CosFile();
        TransferManager manager =null;
        try {
            manager =cosFile.createTransferManager();
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(contextLength);

            PutObjectRequest putObjectRequest = new PutObjectRequest(cosFile.getBucket(), data.getKey(), in,objectMetadata);
            Upload upload = manager.upload(putObjectRequest);
            UploadResult uploadResult = upload.waitForUploadResult();

            System.out.println(cosFile);
        }catch (Exception e){
            System.out.println(e);
        }
        cosFile.shutdownTransferManager(manager);
        return cosFile.getFullPath(data.getKey());

//        String s="abc";
//        FileInputStream fis="";

//        FileInputStream fis =new FileInputStream(new File(data.getFileName()));
    }
    @Override
    public Integer saveImage(ProjectContextDTO image) {

//        byte data[] =image.getSrc().getBytes();
//        InputStream inputStream = new ByteArrayInputStream(data);


//        this.writeFile(image,inputStream,data.length);


        GraphProjectImage result =null;

        if(null!=image.getProjectId()){
            LambdaQueryWrapper<GraphProjectImage> queryWrapper = new LambdaQueryWrapper<GraphProjectImage>();
            queryWrapper.eq(GraphProjectImage::getProjectId,image.getProjectId());
            result = imageMapper.selectOne(queryWrapper);
        }

        String[] files = image.getFileName().split("\\.");


        if(null!=result){
            result.setFileName(image.getFileName());
            result.setFileKey(image.getKey());

            if(files.length>1){
                result.setFileType(files[1]);
            }else {
                result.setFileType("unknow");
            }

            result.setSrc(image.getSrc());
            imageMapper.updateById(result);
            return image.getId();
        }else {
            result = new  GraphProjectImage();
            result.setFileName(image.getFileName());
            if(files.length>1){
                result.setFileType(files[1]);
            }else {
                result.setFileType("unknow");
            }
            result.setProjectId(image.getProjectId());
            result.setFileKey(image.getKey());
            result.setSrc(image.getSrc());
           imageMapper.insert(result);
            return result.getId();
        }



    }

    <T> T jsonToObj(Object o,Class<T> classOfT){
        Gson gson =new Gson();

        return  gson.fromJson((String)o, classOfT);
    }
    Map jsonStrToMap(Object o){
        Gson gson =new Gson();
      return gson.fromJson((String)o, LinkedHashMap.class);
    }
    String toJsonStr(Object o){
        Gson gson =new Gson();
        return gson.toJson(o);
    }

    @Override
    public Integer saveProjectContext(ProjectContextDTO context) {

        GraphProjectContext result =null;

        if(null!=context.getId()){
            LambdaQueryWrapper<GraphProjectContext> queryWrapper = new LambdaQueryWrapper<GraphProjectContext>();
            queryWrapper.eq(GraphProjectContext::getId,context.getId());
            result = contextMapper.selectOne(queryWrapper);
        }

        if(null!=result){
            result.setName(context.getName());
            result.setProjectId(context.getProjectId());
            result.setLayer(context.getLayer());
            result.setSort(context.getOrder());
            result.setProperty(toJsonStr(context.getProperty()));
            result.setScale(toJsonStr(context.getScale()));
            result.setTransform(toJsonStr(context.getTransform()));
            contextMapper.updateById(result);
            return result.getId();
        }else {
            result = new  GraphProjectContext();
            result.setName(context.getName());
            result.setProjectId(context.getProjectId());
            result.setLayer(context.getLayer());
            result.setSort(context.getOrder());
            result.setProperty(toJsonStr(context.getProperty()));
            result.setScale(toJsonStr(context.getScale()));
            result.setTransform(toJsonStr(context.getTransform()));
            contextMapper.insert(result);
            return result.getId();
        }



    }

    @Override
    public Integer deleteContext(Integer id) {
        GraphProjectContext result =null;

        if(null!=id){
            LambdaQueryWrapper<GraphProjectContext> queryWrapper = new LambdaQueryWrapper<GraphProjectContext>();
            queryWrapper.eq(GraphProjectContext::getId,id);
            result = contextMapper.selectOne(queryWrapper);
        }


        if(null != result){
            contextMapper.deleteById(result);
        }


        return 0;
    }

    @Override
    public String uploadFile(String fileName, String key, MultipartFile file) {
String s ="";

        try {
            ProjectContextDTO image =new ProjectContextDTO();
             image.setKey(key+"/"+fileName);
              s= this.writeFile(image,file.getInputStream(),file.getSize());

        } catch (IOException e) {
            e.printStackTrace();
        }
        return s;


    }

    @Override
    public void exportZip(ExportDTO exportDTO, HttpServletResponse response) {
        GraphProjectVO projectVO = findByProjectId(exportDTO.getId());
        GraphProjectImage image = projectVO.getImage();

        List<GraphProjectContext>contexts = projectVO.getList();
        List<ImageFileDTO> list = new ArrayList<>();

        try {
          this.getFileStream(image.getFileKey(),(stream)->{
              BufferedImage bigImage = ImageIO.read(stream);
              contexts.forEach(context->{
                  TransFormDTO transForm = (TransFormDTO)context.getTransform();
                  BufferedImage smallImage=new BufferedImage(transForm.getW(),transForm.getH(),bigImage.getType());

                  Graphics2D gr = smallImage.createGraphics();

                  int x= transForm.getX().intValue();
                  int y = transForm.getY().intValue();
                  gr.drawImage(bigImage,0,0,transForm.getW(),transForm.getH(),
                          x,y,x+transForm.getW(),y+transForm.getH(),
                          null);
                  gr.dispose();

                  ImageFileDTO fileDTO = new ImageFileDTO();
                  fileDTO.setFileName(context.getName()+".png");
                  fileDTO.setImage(smallImage);
                  list.add(fileDTO);
              });
              response.reset();
              response.setCharacterEncoding("UTF-8");
              response.addHeader("Access-Control-Allow-Origin", "*");
              response.setHeader("Access-Control-Expose-Headers", "*");
              response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(image.getFileName()+".zip", "UTF-8"));
              response.setContentType("application/octet-stream;charset=UTF-8");
              OutputStream outputStream = response.getOutputStream();
              ZipOutputStream out = new ZipOutputStream(outputStream);


              try {
                  out.putNextEntry(new ZipEntry(image.getFileName()));
                  ImageIO.write(bigImage,image.getFileType(),out);
//                  ImageIO.write(bufferedImage,"png",out);
                  out.closeEntry();
                  out.flush();


                  for(int i=0;i<list.size();i++){
                      ImageFileDTO dto =list.get(i);
                      BufferedImage bufferedImage = dto.getImage();
                      out.putNextEntry(new ZipEntry(dto.getFileName()));
                      ImageIO.write(bufferedImage,"png",out);
                      out.closeEntry();
                      out.flush();
                  }






                  out.close();
                  outputStream.close();

//                      ImageIO.write(list.get(i),"png",new File("/"+i+".png"));
              } catch (Exception e) {
                  e.printStackTrace();
              }
//


//              out.putNextEntry(new ZipEntry());



              System.out.println();
          });


//



        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public List<GraphProject> getList(GraphProject graphProject) {

        LambdaQueryWrapper<GraphProject> queryWrapper = new LambdaQueryWrapper<GraphProject>();
        return projectMapper.selectList(queryWrapper);
    }
}
